package com.appleyk.mybatis.v1.registrar;

import com.appleyk.mybatis.annotation.MyMapperScan;
import com.appleyk.mybatis.v1.factorybean.UserMapperFactoryBean;
import com.appleyk.mybatis.v1.scanner.MyClassPathMapperScan;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

/**
 * <p>越努力，越幸运</p>
 *
 * @author appleyk
 * @version V.0.1.1
 * @blob https://blog.csdn.net/appleyk
 * @date created on  1:10 上午 2020/12/12
 */
public class UserMapperBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    private static final String PACKAGE_FLAG = "basePackage";

    /**
     * 在这个方法里面对userMapper接口进行"偷天换日"，将其用代理对象进行替换
     * @param annotationMetadata 加注解的元信息（配置类）
     * @param registry bean注册器（其实就是bean ioc）
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        // 先从导入的注解元信息对象annotationMetadata中拿到相应的属性信息
        Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(MyMapperScan.class.getName());
        Object basePackage = attributes.get(PACKAGE_FLAG);
        String basePackageStr = basePackage.toString();
        // new我们自定义的mapper路径扫描器
        MyClassPathMapperScan mapperScan = new MyClassPathMapperScan(registry);
        // 添加bean可以被扫描作为bean定义持有者的filter（因为在spring框架中，接口是不能被作为BeanDefinitionHolder的，因此下面要放开条件）
        mapperScan.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                // 管他接口不接口的，统一放行，直接返回true
                return true;
            }
        });
        // 开始真正的扫包了，调用父类ClassBeanDefinitionScanner的doScan方法
        Set<BeanDefinitionHolder> beanDefinitionHolders = mapperScan.doScan(basePackageStr);
        // 下面遍历获取到的指定basePackages下面的所有mapper的bean定义
        for (BeanDefinitionHolder holder : beanDefinitionHolders) {
            // 1、首先，获取holder的bean定义对象
            GenericBeanDefinition bd = (GenericBeanDefinition) holder.getBeanDefinition();
            // 2、直接重新设置bd的class(因为bd原来的class是接口类型的，无法被Spring IOC进行实例化，得定制（动态代理）)
            bd.setBeanClass(UserMapperFactoryBean.class);
            System.out.println("=== UserMapper偷天换日成功，接下来就可以见证奇迹了！！！！");
        }
    }
}
